package jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.*;

public class JwtTest {

    // 密钥
    private static String TOKEN_KEY = "wwj";

    /**
     * 生成JWT
     * @return
     */
    public static String createToken() {
        Map<String, Object> hearder = new HashMap<String, Object>();
        hearder.put("alg", "HS256");
        hearder.put("typ", "JWT");
        hearder.put("cty", "xxx");
        hearder.put("aaa", "bbb");

        // 设置JWT令牌的过期时间为7天
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE,7);

        String sign = JWT.create()
                .withKeyId("KeyId") // KetId ==>kid
                .withHeader(hearder)// Header（头部）

                .withSubject("this is test token") //主题 ==> sub
                .withAudience("APP", "FrontEnd") //观众 可以理解谁接受签名 ==> aud
                .withNotBefore(new Date()) // 代表这个JWT生效的开始时间，意味着在这个时间之前验证JWT会失败 ==>nbf
                .withClaim("UserId", 123) //Payload（负载内容1）
                .withClaim("UserName", "wwj") //Payload（负载内容2）
                .withIssuer("SERVICE") //发布者 ==>iss
                .withExpiresAt(instance.getTime()) // 过期时间 ==>exp
                .withIssuedAt(new Date())  //设置 生成签名的时间 ==>iat
                .withJWTId("JwtId") //JWTId ==>jti

                .sign(Algorithm.HMAC256(TOKEN_KEY)); //Signature（签名）

        return sign;
    }

    /**
     * HEADER:
     * {
     *   "aaa": "bbb",
     *   "kid": "KeyId",
     *   "cty": "xxx",
     *   "typ": "JWT",
     *   "alg": "HS256"
     * }
     * PAYLOAD:
     * {
     *   "sub": "this is test token",
     *   "aud": [
     *     "APP",
     *     "FrontEnd"
     *   ],
     *   "nbf": 1618886726,
     *   "UserName": "wwj",
     *   "UserId": 123,
     *   "iss": "SERVICE",
     *   "exp": 1619491526,
     *   "iat": 1618886726,
     *   "jti": "JwtId"
     * }
     * SIGNATURE:
     * 根据Headerbase64编码、Payload的base64编码和选定的算法生成
     */

    /**
     * 解析JWT
     * @param token
     */
    public static void decodeToken(String token) {
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(TOKEN_KEY)).build();
        DecodedJWT verify = jwtVerifier.verify(token);

        System.out.println("====================DecodedJWT接口中的方法====================");
        String Header = verify.getHeader();
        System.out.println("Header:" + Header);

        String payload = verify.getPayload();
        System.out.println("payload:" + payload);

        String signature = verify.getSignature();
        System.out.println("signature:" + signature);

        String token1 = verify.getToken();
        System.out.println("token:" + token1);

        System.out.println("====================Header接口中的方法====================");
        String algorithm = verify.getAlgorithm();
        System.out.println("Header-alg:" + algorithm);

        String type = verify.getType();
        System.out.println("Header-typ:" + type);

        String contentType = verify.getContentType();
        System.out.println("Header-cty:" + contentType);

        String keyId = verify.getKeyId();
        System.out.println("deader-kid:" + keyId);

        Claim algClaim = verify.getHeaderClaim("alg");
        if (algClaim.isNull()) {
            System.out.println("Header-alg:null");
        }
        else {
            System.out.println("Header-alg:" + algClaim.asString());
        }
        Claim typClaim = verify.getHeaderClaim("typ");
        if (typClaim.isNull()) {
            System.out.println("Header-typ:null");
        }
        else {
            System.out.println("Header-typ:" + typClaim.asString());
        }
        Claim kidClaim = verify.getHeaderClaim("kid");
        if (kidClaim.isNull()) {
            System.out.println("Header-kid:null");
        }
        else {
            System.out.println("Header-kid:" + kidClaim.asString());
        }
        Claim ctyClaim = verify.getHeaderClaim("cty");
        if (ctyClaim.isNull()) {
            System.out.println("Header-cty:null");
        }
        else {
            System.out.println("Header-cty:" + ctyClaim.asString());
        }
        Claim aaaClaim = verify.getHeaderClaim("aaa");
        if (ctyClaim.isNull()) {
            System.out.println("Header-aaa:null");
        }
        else {
            System.out.println("Header-aaa:" + aaaClaim.asString());
        }

        System.out.println("====================Payload接口中的方法====================");
        String issuer = verify.getIssuer();
        System.out.println("Payload-iss:" + issuer);

        String subject = verify.getSubject();
        System.out.println("Payload-sub:" + subject);

        List<String> audience = verify.getAudience();
        System.out.println("Payload-aud:");
        if (audience == null) {
            System.out.println("    JWT未设置Audience,为null");
        }
        else {
            audience.stream().forEach(str -> System.out.println("    " + str));
        }

        Date expiresAt = verify.getExpiresAt();
        System.out.println("Payload-exp:" + expiresAt);

        Date notBefore = verify.getNotBefore();
        System.out.println("Payload-nbf:" + notBefore);

        Date issuedAt = verify.getIssuedAt();
        System.out.println("Payload-iat:" + issuedAt);

        String id = verify.getId();
        System.out.println("Payload-jti:" + id);

        Map<String, Claim> claimsMap = verify.getClaims();
        System.out.println("Payload的自定义内容:");
        if (claimsMap.size() == 0) {
            System.out.println("JWT的Payload为null");
        }
        else {
            claimsMap.forEach((k, v) -> {
                System.out.println("    Key = " + k + ", Value = "+ v);
            });
        }

        Claim subClaim = verify.getClaim("sub");
        if (subClaim.isNull()) {
            System.out.println("Payload-sub:null");
        }
        else {
            System.out.println("Payload-sub:" + subClaim.asString());
        }
        Claim userNameClaim = verify.getClaim("UserName");
        if (userNameClaim.isNull()) {
            System.out.println("Payload-UserName:null");
        }
        else {
            System.out.println("Payload-UserName:" + userNameClaim.asString());
        }
        Claim userIdClaim = verify.getClaim("UserId");
        if (userIdClaim.isNull()) {
            System.out.println("Payload-UserId:null");
        }
        else {
            System.out.println("Payload-UserId:" + userIdClaim.asInt());
        }
        Claim issClaim = verify.getClaim("iss");
        if (issClaim.isNull()) {
            System.out.println("Payload-iss:null");
        }
        else {
            System.out.println("Payload-iss:" + issClaim.asString());
        }
        Claim audClaim = verify.getClaim("aud");
        System.out.println("audience:");
        if (audClaim.isNull()) {
            System.out.println("    JWT未设置Audience,为null");
        }
        else {
            List<String> audClaimList = audClaim.asList(String.class);
            audClaimList.stream().forEach(str -> System.out.println("    " + str));
        }
        Claim nbfClaim = verify.getClaim("nbf");
        if (nbfClaim.isNull()) {
            System.out.println("Payload-nbf:null");
        }
        else {
            System.out.println("Payload-nbf:" + nbfClaim.asDate());
        }
        Claim expClaim = verify.getClaim("exp");
        if (expClaim.isNull()) {
            System.out.println("Payload-exp:null");
        }
        else {
            System.out.println("Payload-exp:" + expClaim.asDate());
        }
        Claim iatClaim = verify.getClaim("iat");
        if (iatClaim.isNull()) {
            System.out.println("Payload-iat:null");
        }
        else {
            System.out.println("Payload-iat:" + iatClaim.asDate());
        }
        Claim jtiClaim = verify.getClaim("jti");
        if (jtiClaim.isNull()) {
            System.out.println("Payload-jti:null");
        }
        else {
            System.out.println("Payload-jti:" + jtiClaim.asString());
        }
    }

    public static void main(String[] args) {
        String token = createToken();
        decodeToken(token);
    }

}
